#ifndef __L_FMT_H__
#define __L_FMT_H__

#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <ctime>
#include <memory>
#include "level.hpp"
#include "util.hpp"
#include "message.hpp"

namespace Log
{
    //1.抽象格式化子项的父类
    class FormatItem
    {
    public:
        using ptr = std::shared_ptr<FormatItem>;
        virtual void Format(std::ostream &out, const LogMessage &logmsg) = 0;
    };

    //2.派生具体的格式化子类: 主体消息子类, 时间子类, 日志等级消息子类, 源文件子类, 行号子类, 线程ID子类, 日志器子类, 水平制表符子类, 换行子类, 其他子类
    //主体消息子类
    class MessageFormatItem : public FormatItem
    {
    public:
        void Format(std::ostream& out, const LogMessage& logmsg) override
        {
            out << logmsg._payLoad;
        }
    };

    //时间子类
    class TimeFormatItem : public FormatItem
    {
    public:
        TimeFormatItem(const std::string& fmt = "%H:%M:%S")
        :_fmt(fmt)
        {} 
        void Format(std::ostream &out, const LogMessage &logmsg) override
        {
            struct tm currtime;
            localtime_r(&logmsg._ctime, &currtime);
            char tmp[64];
            strftime(tmp, sizeof(tmp) - 1, _fmt.c_str(), &currtime);
            out << tmp;
        }
    private:
        std::string _fmt;
    };

    //日志等级子类
    class LevelFormatItem : public FormatItem
    {
    public:
        void Format(std::ostream &out, const LogMessage &logmsg) override
        {
            out << LogLevel::ToString(logmsg._level);
        }
    };

    //源文件子类
    class FileFormatItem : public FormatItem
    {
    public:
        void Format(std::ostream &out, const LogMessage &logmsg) override
        {
            out << logmsg._file;
        }
    };

    //行号子类
    class LineFormatItem : public FormatItem
    {
    public:
        void Format(std::ostream &out, const LogMessage &logmsg) override
        {
            out << logmsg._line;
        }
    };

    //线程ID子类
    class TidFormatItem : public FormatItem
    {
    public:
        void Format(std::ostream &out, const LogMessage &logmsg) override
        {
            out << logmsg._tid;
        }
    };

    //日志器子类
    class LoggerFormatItem : public FormatItem
    {
    public:
        void Format(std::ostream &out, const LogMessage &logmsg) override
        {
            out << logmsg._logger;
        }
    };

    //水平制表符子类
    class TabFormatItem : public FormatItem
    {
    public:
        void Format(std::ostream &out, const LogMessage &logmsg) override
        {
            out << "\t";
        }
    };

    //换行子类
    class NewLineFormatItem : public FormatItem
    {
    public:
        void Format(std::ostream &out, const LogMessage &logmsg) override
        {
            out << "\n";
        }
    };

    //其他子类
    class OtherFormatItem : public FormatItem
    {
    public:
        OtherFormatItem(const std::string& str = "")
        :_str(str)
        {

        } 
        void Format(std::ostream &out, const LogMessage &logmsg) override
        {
            out << _str;
        }
    private:
        std::string _str;
    };


    //格式化类

    /*
        %d{%H:%M:%S} 表示时间
        %t 表示线程id
        %f 表示源文件
        %l 表示行号
        %p 表示日志等级
        %c 表示日志器名称
        %T 表示水平制表缩进
        %m 表示日志主体消息
        %n 表示换行
    */
    class Formatter
    {
    public:
        using ptr = std::shared_ptr<Formatter>;
        Formatter(const std::string &pattern = "[%d{%H:%M:%S}][%t][%f:%l]:[%p][%c]%T%m%n")
            : _pattern(pattern)
        {
            if(ParsePattern() == false)
            {
                // 解析格式化串出错就直接退出进程;
                std::cout << "格式化字符串解析错误!" << std::endl;
                abort();
            }
        }

        //对message进行格式化
        void format(std::ostream &out, const LogMessage &msg)
        {
            for(const auto& item : _items)
            {
                item->Format(out, msg);
            }
        }
        std::string format(const LogMessage &msg)
        {
            std::stringstream ss;
            format(ss, msg);
            return ss.str();
        }

    private:
        //根据不同的格式化字符创建不同的格式化子项对象
        FormatItem::ptr CreateItem(const std::string &key, std::string &val)
        {
            if(key == "d")
            {
                if(val == "")
                {
                    val = "%H:%M:%S";
                }
                return std::make_shared<TimeFormatItem>(val);
            }
            if(key == "t")
            {
                return std::make_shared<TidFormatItem>();
            }
            if(key == "f")
            {
                return std::make_shared<FileFormatItem>();
            }
            if(key == "l")
            {
                return std::make_shared<LineFormatItem>();
            }
            if(key == "p")
            {
                return std::make_shared<LevelFormatItem>();
            }
            if(key == "c")
            {
                return std::make_shared<LoggerFormatItem>();
            }
            if(key == "T")
            {
                return std::make_shared<TabFormatItem>();
            }
            if(key == "m")
            {
                return std::make_shared<MessageFormatItem>();
            }
            if(key == "n")
            {
                return std::make_shared<NewLineFormatItem>();
            }
            if(key.empty())
            {
                //如果key值是空字符那么, 就说明是其他子项子类
                return std::make_shared<OtherFormatItem>(val);
            }
            std::cout << "没有对应的格式化字符: %" << key << std::endl;
            abort();  //直接终止程序
            return FormatItem::ptr();   //返回一个空指针
        }

        // 对格式化字符串进行解析
        // ab%%cde[%d{%H:%M:%S}][%p]%T%m%n
        bool ParsePattern()
        {
            std::vector<std::pair<std::string, std::string>> fmt_order;
            std::string key = "";
            std::string val = "";
            int pos = 0;
            while (pos < _pattern.size())
            {
                // 对原始字符串进行处理, 判断是否为%
                if (_pattern[pos] != '%')
                {
                    val.push_back(_pattern[pos++]);
                    continue;
                }

                // 走到这里说明pos位置的字符为%, 再看pos+1位置的字符是否为%
                if (pos + 1 < _pattern.size() && _pattern[pos + 1] == '%')
                {
                    val.push_back(_pattern[pos]);
                    pos += 2; // 跳过两个%
                    continue;
                }
                if (val.empty() == false)
                {
                    fmt_order.push_back(std::make_pair(key, val));
                    val.clear();
                }

                // 走到这里说明pos位置的字符为%, 并且pos+1位置的字符也不是%
                pos += 1;
                if (pos == _pattern.size())
                {
                    std::cout << "%之后,没有对应的格式化字符!\n";
                    return false;
                }
                key = _pattern[pos];
                // 判断时间格式字符后面是否有子格式, 即判断后面是否有{, 如果不是时间的格式化字符就直接按照常规字符处理{}
                bool err_flag = true;
                if (pos + 1 < _pattern.size() 
                && key == "d" 
                && _pattern[pos + 1] == '{')
                {
                    pos += 2; // pos指向了子格式{之后的位置
                    while (pos < _pattern.size() && _pattern[pos] != '}')
                    {
                        val.push_back(_pattern[pos++]);
                    }
                    // 走到这要么没有找到}, 要么pos位置的字符为}
                    if (pos >= _pattern.size())
                    {
                        err_flag = false;
                        std::cout << "子规则{}匹配错误!" << std::endl;
                        return err_flag;
                    }
                }
                //走到这里说明格式化字符后面没有子格式
                fmt_order.push_back(std::make_pair(key, val));
                key.clear();
                val.clear();
                pos += 1;
            }

            for (auto &fmt : fmt_order)
            {
                _items.push_back(CreateItem(fmt.first, fmt.second));
            }
            return true;
        }

    private:
        std::string _pattern;   //格式化规则字符串
        std::vector<FormatItem::ptr> _items;
    };
}
#endif